/* NOTES TO REMEMBER
 * Could add
 * - hitboxes to all objects to make collision better
 * - levels
 * - bosses
 * - explosions / particles
 * - parallax background
 * - vectors for movement
 * - lirbraries! http://www.createjs.com/#!/CreateJS
 */

/* RESOURCES
 * http://www.w3schools.com/html5/html5_ref_av_dom.asp
 * http://www.superflashbros.net/as3sfxr/
 */

/**
 * Initialize the Game and start it.
 */

var game = new Game();

function init() {
	game.init();
}

/**
 * Define an object to hold all our images for the game so images
 * are only ever created once. This type of object is known as a
 * singleton.
 */
var imageRepository = new function () {
	// Define images
	this.background = new Image();
	this.spaceship = new Image();
	this.bullet = new Image();
	this.feulship = new Image();
	this.techStatus = new Image();
	this.feulstation = new Image();
	this.enemyBullet = new Image();
	this.frozenship = new Image();
    this.tecFace = new Image();

	// Ensure all images have loaded before starting the game
	var numImages = 8;
	var numLoaded = 0;
	function imageLoaded() {
		numLoaded++;
		if (numLoaded === numImages) {
			window.init();
		}
	}
	this.background.onload = function () {
		imageLoaded();
	}
	this.feulship.onload = function () {
		imageLoaded();
	}
	this.spaceship.onload = function () {
		imageLoaded();
	}
	this.bullet.onload = function () {
		imageLoaded();
	}

	this.enemyBullet.onload = function () {
		imageLoaded();
	}

	this.techStatus.onload = function () {
		imageLoaded();
	}
	this.feulstation.onload = function () {
		imageLoaded();
	}
	this.frozenship.onload = function () {
		imageLoaded();
	}
    this.tecFace.onload = function () {
		imageLoaded();
	}

	// Set images src
	this.background.src = "imgs/bg.png";
	this.spaceship.src = "imgs/ship.png";
	this.bullet.src = "imgs/bullet.png";
	this.enemyBullet.src = "imgs/meteor2.png";
	this.feulship.src = "imgs/feulShip.png";
	this.techStatus.src = "imgs/smile1.png";
	this.feulstation.src = "imgs/feulStation.png";
	this.frozenship.src = "imgs/freezeship.png";
    this.tecFace.src = "imgs/smile2.png";
}

/**
 * Creates the Drawable object which will be the base class for
 * all drawable objects in the game. Sets up defualt variables
 * that all child objects will inherit, as well as the defualt
 * functions.
 */
function Drawable() {
	this.init = function (x, y, width, height) {
		// Defualt variables
		this.x = x;
		this.y = y;
		this.width = width;
		this.height = height;
	}

	this.speed = 0;
	this.canvasWidth = 0;
	this.canvasHeight = 0;
	this.collidableWith = "";
	this.isColliding = false;
	this.type = "";

	// Define abstract function to be implemented in child objects
	this.draw = function () {};
	this.move = function () {};
	this.setSpeed = function (speed) {
		this.speed = speed;
	};
	this.isCollidableWith = function (object) {
		return (this.collidableWith === object.type);
	};
}

function FeulShip() {

	this.collidableWith = "";
	this.type = "feulShip";
	this.init = function (x, y, width, height) {
		this.x = x;
		this.y = y;
		this.width = width;
		this.height = height;
	}
	this.gaveFeul = false;
	this.alive = true;
	this.speedX = 3;
	this.speedY = 3;
	this.draw = function () {
		this.context.drawImage(imageRepository.feulship, this.x, this.y);
        freezeShip = true;
	};
	this.clear = function () {
		this.context.clearRect(this.x - 1, this.y - 1, this.width + 2, this.height + 2);
		this.x = 0;
		this.y = 0;
		this.alive = false;
		this.gaveFeul = false;
	}
	this.move = function () {
		this.context.clearRect(this.x - 1, this.y - 1, this.width + 2, this.height + 2);
		this.x = this.x + this.speedX >= game.ship.x - 30 ? this.x : this.x + this.speedX;
		this.y = this.y + this.speedY >= game.ship.y - 30 ? this.y : this.y + this.speedY;
		this.draw();
		if (this.x + 50 >= game.ship.x && this.y + 50 >= game.ship.y && !this.gaveFeul) {
			feulFillBySpaceship();
			game.score.alive = true;

            game.faulFill.get();
			game.score.init(this.x + 2, this.y + 2, scenario.fs_spaceshipCost, false);
			game.score.move();
			scoreEnd = currentTime + scoreTime;
			this.gaveFeul = true;
			this.clear();
		}

	};
}
FeulShip.prototype = new Drawable();

function FeulStation(speed) {

	this.collidableWith = "ship";
	this.type = "feulstation";
	this.init = function (x, y, width, height) {
		this.x = x;
		this.y = y;
		this.width = width;
		this.height = height;
	}
	this.alive = false;
	this.isColliding = false;
	this.speed = speed;

	this.draw = function () {
		this.context.drawImage(imageRepository.feulstation, this.x, this.y);

	};

	this.move = function () {
		if (this.isColliding) {
         game.faulFill.get();
			feulFillDone();
			game.score.alive = true;
			game.score.init(this.x + 2, this.y + 2, scenario.getFeulFillCost(), false);
			game.score.move();
			scoreEnd = currentTime + scoreTime;
			this.alive = false;
			this.isColliding = false;

			this.context.clearRect(this.x - 1, this.y - 1, this.width + 2, this.height + 2);
			this.x = -this.width;
			this.y = -this.height;

		} else if (this.y >= Background.prototype.canvasHeight) {
			this.alive = false;
			this.context.clearRect(this.x - 1, this.y - 1, this.width + 2, this.height + 2);
		} else if (this.y < Background.prototype.canvasHeight) {
			this.context.clearRect(this.x - 1, this.y - 1, this.width + 2, this.height + 2);
			this.y += this.speed;
			this.alive = true;
			this.draw();

		}
	};
}
FeulStation.prototype = new Drawable();

/**
 * Creates the Background object which will become a child of
 * the Drawable object. The background is drawn on the "background"
 * canvas and creates the illusion of moving by panning the image.
 */
function Background(speed) {
	this.speed = speed; // Redefine speed of the background for panning
	this.setSpeed = function (speed) {
		this.speed = speed;
	}
	// Implement abstract function
	this.draw = function () {
		// Pan background
		this.y += this.speed;
		//this.context.clearRect(0,0, this.canvasWidth, this.canvasHeight);
		this.context.drawImage(imageRepository.background, this.x, this.y);

		// Draw another image at the top edge of the first image
		this.context.drawImage(imageRepository.background, this.x, this.y - this.canvasHeight);

		// If the image scrolled off the screen, reset
		if (this.y >= this.canvasHeight)
			this.y = 0;
	};
}
// Set Background to inherit properties from Drawable
Background.prototype = new Drawable();

function TechStatus() {
	this.status = 1;

	this.draw = function () {
		this.context.drawImage(imageRepository.techStatus, 60, 75);

	};
	this.changeStatus = function (status) {
		imageRepository.techStatus.src = "imgs/smile" + status + ".png";
		this.status = status;

	};
};

// Set Background to inherit properties from Drawable
TechStatus.prototype = new Drawable();

/**
 * Creates the Bullet object which the ship fires. The bullets are
 * drawn on the "main" canvas.
 */
function Bullet(object) {
	this.alive = false; // Is true if the bullet is currently in use
	var self = object;
	/*
	 * Sets the bullet values
	 */
	this.spawn = function (x, y, speed) {
		this.x = x;
		this.y = y;
		this.speed = speed;
		this.alive = true;
	};

	/*
	 * Uses a "drity rectangle" to erase the bullet and moves it.
	 * Returns true if the bullet moved of the screen, indicating that
	 * the bullet is ready to be cleared by the pool, otherwise draws
	 * the bullet.
	 */
	this.draw = function () {
		this.context.clearRect(this.x - 1, this.y - 1, this.width + 2, this.height + 2);
		this.y -= this.speed;

		if (this.isColliding) {

			game.explosion.get();
			this.isColliding = false;

			return true;
		} else if (self === "bullet" && this.y <= 0 - this.height) {
			return true;
		} else if (self === "enemyBullet" && this.y >= this.canvasHeight) {
			return true;
		} else {
			if (self === "bullet") {
				this.context.drawImage(imageRepository.bullet, this.x, this.y);
			} else if (self === "enemyBullet") {
				this.context.drawImage(imageRepository.enemyBullet, this.x, this.y);
			}

			return false;
		}

	};

	/*
	 * Resets the bullet values
	 */
	this.clear = function () {
		this.x = 0;
		this.y = 0;
		this.speed = 0;
		this.alive = false;
		this.isColliding = false;
	};
}
Bullet.prototype = new Drawable();

/**
 * QuadTree object.
 *
 * The quadrant indexes are numbered as below:
 *     |
 *  1  |  0
 * ----+----
 *  2  |  3
 *     |
 */
function QuadTree(boundBox, lvl) {
	var maxObjects = 10;
	this.bounds = boundBox || {
		x : 0,
		y : 0,
		width : 0,
		height : 0
	};
	var objects = [];
	this.nodes = [];
	var level = lvl || 0;
	var maxLevels = 5;

	/*
	 * Clears the quadTree and all nodes of objects
	 */
	this.clear = function () {
		objects = [];

		for (var i = 0; i < this.nodes.length; i++) {
			this.nodes[i].clear();
		}

		this.nodes = [];
	};

	/*
	 * Get all objects in the quadTree
	 */
	this.getAllObjects = function (returnedObjects) {
		for (var i = 0; i < this.nodes.length; i++) {
			this.nodes[i].getAllObjects(returnedObjects);
		}

		for (var i = 0, len = objects.length; i < len; i++) {
			returnedObjects.push(objects[i]);
		}

		return returnedObjects;
	};

	/*
	 * Return all objects that the object could collide with
	 */
	this.findObjects = function (returnedObjects, obj) {
		if (typeof obj === "undefined") {
			//console.log("UNDEFINED OBJECT");
			return;
		}

		var index = this.getIndex(obj);
		if (index != -1 && this.nodes.length) {
			this.nodes[index].findObjects(returnedObjects, obj);
		}

		for (var i = 0, len = objects.length; i < len; i++) {
			returnedObjects.push(objects[i]);
		}

		return returnedObjects;
	};

	/*
	 * Insert the object into the quadTree. If the tree
	 * excedes the capacity, it will split and add all
	 * objects to their corresponding nodes.
	 */
	this.insert = function (obj) {
		if (typeof obj === "undefined") {
			return;
		}

		if (obj instanceof Array) {
			for (var i = 0, len = obj.length; i < len; i++) {
				this.insert(obj[i]);
			}

			return;
		}

		if (this.nodes.length) {
			var index = this.getIndex(obj);
			// Only add the object to a subnode if it can fit completely
			// within one
			if (index != -1) {
				this.nodes[index].insert(obj);

				return;
			}
		}

		objects.push(obj);

		// Prevent infinite splitting
		if (objects.length > maxObjects && level < maxLevels) {
			if (this.nodes[0] == null) {
				this.split();
			}

			var i = 0;
			while (i < objects.length) {

				var index = this.getIndex(objects[i]);
				if (index != -1) {
					this.nodes[index].insert((objects.splice(i, 1))[0]);
				} else {
					i++;
				}
			}
		}
	};

	/*
	 * Determine which node the object belongs to. -1 means
	 * object cannot completely fit within a node and is part
	 * of the current node
	 */
	this.getIndex = function (obj) {

		var index = -1;
		var verticalMidpoint = this.bounds.x + this.bounds.width / 2;
		var horizontalMidpoint = this.bounds.y + this.bounds.height / 2;

		// Object can fit completely within the top quadrant
		var topQuadrant = (obj.y < horizontalMidpoint && obj.y + obj.height < horizontalMidpoint);
		// Object can fit completely within the bottom quandrant
		var bottomQuadrant = (obj.y > horizontalMidpoint);

		// Object can fit completely within the left quadrants
		if (obj.x < verticalMidpoint &&
			obj.x + obj.width < verticalMidpoint) {
			if (topQuadrant) {
				index = 1;
			} else if (bottomQuadrant) {
				index = 2;
			}
		}
		// Object can fix completely within the right quandrants
		else if (obj.x > verticalMidpoint) {
			if (topQuadrant) {
				index = 0;
			} else if (bottomQuadrant) {
				index = 3;
			}
		}

		return index;
	};

	/*
	 * Splits the node into 4 subnodes
	 */
	this.split = function () {
		// Bitwise or [html5rocks]
		var subWidth = (this.bounds.width / 2) | 0;
		var subHeight = (this.bounds.height / 2) | 0;

		this.nodes[0] = new QuadTree({
				x : this.bounds.x + subWidth,
				y : this.bounds.y,
				width : subWidth,
				height : subHeight
			}, level + 1);
		this.nodes[1] = new QuadTree({
				x : this.bounds.x,
				y : this.bounds.y,
				width : subWidth,
				height : subHeight
			}, level + 1);
		this.nodes[2] = new QuadTree({
				x : this.bounds.x,
				y : this.bounds.y + subHeight,
				width : subWidth,
				height : subHeight
			}, level + 1);
		this.nodes[3] = new QuadTree({
				x : this.bounds.x + subWidth,
				y : this.bounds.y + subHeight,
				width : subWidth,
				height : subHeight
			}, level + 1);
	};
}

/**
 * Custom Pool object. Holds Bullet objects to be managed to prevent
 * garbage collection.
 * The pool works as follows:
 * - When the pool is initialized, it popoulates an array with
 *   Bullet objects.
 * - When the pool needs to create a new object for use, it looks at
 *   the last item in the array and checks to see if it is currently
 *   in use or not. If it is in use, the pool is full. If it is
 *   not in use, the pool "spawns" the last item in the array and
 *   then pops it from the end and pushed it back onto the front of
 *   the array. This makes the pool have free objects on the back
 *   and used objects in the front.
 * - When the pool animates its objects, it checks to see if the
 *   object is in use (no need to draw unused objects) and if it is,
 *   draws it. If the draw() function returns true, the object is
 *   ready to be cleaned so it "clears" the object and uses the
 *   array function splice() to remove the item from the array and
 *   pushes it to the back.
 * Doing this makes creating/destroying objects in the pool
 * constant.
 */
function Pool(maxSize) {
	this.size = maxSize; // Max bullets allowed in the pool
	var pool = [];
	this.setSize = function (newSize) {
		for (var i = 0; i < this.size; i++) {
			game.mainContext.clearRect(pool[i].x - 1, pool[i].y - 1, pool[i].width + 2, pool[i].height + 2);
			if (pool[i].alive == undefined) {
				pool[i].alive = false;

			}
		}
		this.size = newSize;
	}
	this.getPool = function () {
		var obj = [];
		for (var i = 0; i < this.size; i++) {
			if (pool[i].alive == undefined) {
				pool[i].alive = true;
			}
			if (pool[i].alive) {
				obj.push(pool[i]);
			}
		}
		return obj;
	}

	/*
	 * Populates the pool array with the given object
	 */
	this.init = function (object) {
		if (object == "bullet") {
			for (var i = 0; i < this.size; i++) {
				// Initalize the object
				var bullet = new Bullet("bullet");
				bullet.init(0, 0, imageRepository.bullet.width,
					imageRepository.bullet.height);
				bullet.collidableWith = "enemyBullet";
				bullet.type = "bullet";
				pool[i] = bullet;
			}
		} else if (object == "enemyBullet") {
			for (var i = 0; i < this.size; i++) {
				var bullet = new Bullet("enemyBullet");
				bullet.init(0, 0, imageRepository.enemyBullet.width,
					imageRepository.enemyBullet.height);
				bullet.collidableWith = "ship";
				bullet.type = "enemyBullet";
				pool[i] = bullet;
			}
		}
	};

	/*
	 * Grabs the last item in the list and initializes it and
	 * pushes it to the front of the array.
	 */
	this.get = function (x, y, speed) {
		if (!pool[this.size - 1].alive) {
			pool[this.size - 1].spawn(x, y, speed);
			pool.unshift(pool.pop());
		}
	};

	/*
	 * Used for the ship to be able to get two bullets at once. If
	 * only the get() function is used twice, the ship is able to
	 * fire and only have 1 bullet spawn instead of 2.
	 */
	this.getTwo = function (x1, y1, speed1, x2, y2, speed2) {
		if (!pool[this.size - 1].alive && !pool[this.size - 2].alive) {
			this.get(x1, y1, speed1);
			this.get(x2, y2, speed2);
		}
	};

	/*
	 * Draws any in use Bullets. If a bullet goes off the screen,
	 * clears it and pushes it to the front of the array.
	 */
	this.animate = function () {
		for (var i = 0; i < this.size; i++) {
			// Only draw until we find a bullet that is not alive
			if (pool[i].alive) {
				if (pool[i].draw()) {
					pool[i].clear();
					pool.push((pool.splice(i, 1))[0]);
				}
			} else
				break;
		}
	};
}

/**
 * Create the Ship object that the player controls. The ship is
 * drawn on the "ship" canvas and uses dirty rectangles to move
 * around the screen.
 */
var shipSpeed = 13;
function Ship() {
	this.speed = shipSpeed;
	this.bulletPool = new Pool(60);
	this.fireRate = 15;
	this.counter = 0;
	this.collidableWith = "";
	this.type = "ship";

	this.init = function (x, y, width, height) {
		// Defualt variables
		this.x = x;
		this.y = y;
		this.width = width;
		this.height = height;
		this.alive = true;
		this.isColliding = false;
		this.bulletPool.init("bullet");
	}

	this.draw = function () {
		this.context.drawImage(imageRepository.spaceship, this.x, this.y);
	};
	this.move = function () {
		this.counter++;
		// Determine if the action is move action
		if (KEY_STATUS.left || KEY_STATUS.right ||
			KEY_STATUS.down || KEY_STATUS.up) {
			// The ship moved, so erase it's current image so it can
			// be redrawn in it's new location
			this.context.clearRect(this.x - 0.5, this.y - 0.5, this.width + 1, this.height + 1);

			// Update x and y according to the direction to move and
			// redraw the ship. Change the else if's to if statements
			// to have diagonal movement.
			if (KEY_STATUS.left) {
				this.x -= this.speed
				if (this.x <= 0) // Kep player within the screen
					this.x = 0;
			} else if (KEY_STATUS.right) {
				this.x += this.speed
				if (this.x >= this.canvasWidth - this.width)
					this.x = this.canvasWidth - this.width;
			} else if (KEY_STATUS.up) {
				this.y -= this.speed
				if (this.y <= 0)
					this.y = 0;
			} else if (KEY_STATUS.down) {
				this.y += this.speed
				if (this.y >= this.canvasHeight - this.height)
					this.y = this.canvasHeight - this.height;
			}
		}
		// Redraw the ship
		if (this.isColliding) {

			if (!freezeShip) {

				this.isColliding = false;
				game.explosion.get();
			} else {

				this.isColliding = false;

			}
		}
		this.draw();

		if (KEY_STATUS.space && this.counter >= this.fireRate && !this.isColliding && !freezeShip) {
			this.fire();
			this.counter = 0;

		}
	};

	/*
	 * Fires two bullets
	 */
	this.fire = function () {

		this.bulletPool.getTwo(this.x + 30, this.y, 10,
			this.x + 40, this.y, 10);
		game.laser.get();

	};
}
Ship.prototype = new Drawable();

/**
 * Creates the Game object which will hold all objects and data for
 * the game.
 */
function Game() {
	/*
	 * Gets canvas information and context and sets up all game
	 * objects.
	 * Returns true if the canvas is supported and false if it
	 * is not. This is to stop the animation script from constantly
	 * running on browsers that do not support the canvas.
	 */
	this.init = function () {
		// Get the canvas elements
		this.bgCanvas = document.getElementById('background');
		this.shipCanvas = document.getElementById('ship');
		this.mainCanvas = document.getElementById('main');
		this.feulshipCanvas = document.getElementById('feulship');
		this.techStatusCanvas = document.getElementById('techStatus');
		this.feulStationCanvas = document.getElementById('feulstation');
		this.scoreCanvas = document.getElementById('scoreCan');
        this.scoreFaceCanvas = document.getElementById('scoreCanFace');
           this.alertCanvas = document.getElementById('alertCan');
		// Test to see if canvas is supported. Only need to
		// check one canvas
		if (this.bgCanvas.getContext) {
			this.bgContext = this.bgCanvas.getContext('2d');
			this.shipContext = this.shipCanvas.getContext('2d');
			this.mainContext = this.mainCanvas.getContext('2d');
			this.feulshipContext = this.feulshipCanvas.getContext('2d');
			this.feulStationContext = this.feulStationCanvas.getContext('2d');
			this.techStatusContext = this.techStatusCanvas.getContext('2d');
			this.scoreContext = this.scoreCanvas.getContext('2d');
            this.scoreFaceContext = this.scoreFaceCanvas.getContext('2d');
             this.alertContext = this.alertCanvas.getContext('2d');
			// Initialize objects to contain their context and canvas
			// information
			Background.prototype.context = this.bgContext;
			Background.prototype.canvasWidth = this.bgCanvas.width;
			Background.prototype.canvasHeight = this.bgCanvas.height;

			Ship.prototype.context = this.shipContext;
			Ship.prototype.canvasWidth = this.shipCanvas.width;
			Ship.prototype.canvasHeight = this.shipCanvas.height;

			Bullet.prototype.context = this.mainContext;
			Bullet.prototype.canvasWidth = this.mainCanvas.width;
			Bullet.prototype.canvasHeight = this.mainCanvas.height;

			FeulShip.prototype.context = this.feulshipContext;
			FeulShip.prototype.canvasWidth = this.feulshipCanvas.width;
			FeulShip.prototype.canvasHeight = this.feulshipCanvas.height;

			FeulStation.prototype.context = this.feulStationContext;
			FeulStation.prototype.canvasWidth = this.feulStationCanvas.width;
			FeulStation.prototype.canvasHeight = this.feulStationCanvas.height;

			TechStatus.prototype.context = this.techStatusContext;
			TechStatus.prototype.canvasWidth = this.techStatusCanvas.width;
			TechStatus.prototype.canvasHeight = this.techStatusCanvas.height;

			Score.prototype.context = this.scoreContext;
			Score.prototype.canvasWidth = this.scoreCanvas.width;
			Score.prototype.canvasHeight = this.scoreCanvas.height;

            AlertC.prototype.context = this.alertContext;
			AlertC.prototype.canvasWidth = this.alertCanvas.width;
			AlertC.prototype.canvasHeight = this.alertCanvas.height;

            ScoreFace.prototype.context = this.scoreFaceContext;
			ScoreFace.prototype.canvasWidth = this.scoreFaceCanvas.width;
			ScoreFace.prototype.canvasHeight = this.scoreFaceCanvas.height;

			this.techStatus = new TechStatus();

			// Initialize the background object
			this.background = new Background(1);
			this.background.init(0, 0); // Set draw point to 0,0

			// Initialize the ship object
			this.ship = new Ship();
			// Set the ship to start near the bottom middle of the canvas
			this.shipStartX = this.shipCanvas.width / 2 - imageRepository.spaceship.width;
			this.shipStartY = this.shipCanvas.height / 4 * 3 + imageRepository.spaceship.height;
			this.ship.init(this.shipStartX, this.shipStartY,
				imageRepository.spaceship.width, imageRepository.spaceship.height);

			this.feulstation = new FeulStation(2);
			this.feulstation.alive = false;

			this.score = new Score(14);
			this.score.alive = false;

            this.alertC = new AlertC(20);
			this.alertC.alive = false;

            this.scoreFace = new ScoreFace();
            this.scoreFace.alive = false;

			this.feulship = new FeulShip(scenario.fs_actionTime);
			this.feulship.alive = false;

			this.enemyBulletPool = new Pool(5);
			this.enemyBulletPool.init("enemyBullet");
			this.feulStatus = scenario.maxFeulInventory;
			// Start QuadTree
			this.quadTree = new QuadTree({
					x : 0,
					y : 0,
					width : this.mainCanvas.width,
					height : this.mainCanvas.height
				});

			this.playerScore = 0;

			// Audio files
			this.laser = new SoundPool(10);
			this.laser.init("laser");

			this.explosion = new SoundPool(20);
			this.explosion.init("explosion");

            this.faulFill = new SoundPool(5);
			this.faulFill.init("faulFill");
			//	this.backgroundAudio = new Audio("sounds/kick_shock.wav");
			//	this.backgroundAudio.loop = true;
			//	this.backgroundAudio.volume = .25;
			//	this.backgroundAudio.load();

			this.gameOverAudio = new Audio("sounds/game_over.wav");
			this.gameOverAudio.loop = true;
			this.gameOverAudio.volume = .25;
			this.gameOverAudio.load();

			this.checkAudio = document.getElementById('loading').style.display = "none";
			game.start();
			

		}
	};

	// Start the animation loop
	this.start = function () {
		this.ship.draw();
		//	this.backgroundAudio.play();
		timer.resetStopwatch();
		gameTimer = scenario.gameLength;
        $("#mainCost").html(window.scenario.mc_maintenanceActionCost);
		animate();
		this.feulStatus = scenario.maxFeulInventory;
		if(!pauseGame){
		timer.Timer.play();
        var data = {
			file: window.fileName,
			folder: window.folderName,
			assignmentId: window.assignmentId};

	$.ajax({
		type: "POST",
		url: "../MGGameService.svc/firstData/",
		data: JSON.stringify(data),
		dataType: 'json'
	});
		}
		game.techStatus.changeStatus(1);

	};

	// Restart the game
	this.restart = function () {
		this.gameOverAudio.pause();
		document.getElementById('game-over').style.display = "none";
		this.bgContext.clearRect(0, 0, this.bgCanvas.width, this.bgCanvas.height);
		this.shipContext.clearRect(0, 0, this.shipCanvas.width, this.shipCanvas.height);
		this.mainContext.clearRect(0, 0, this.mainCanvas.width, this.mainCanvas.height);
		this.feulshipContext.clearRect(0, 0, this.feulshipCanvas.width, this.feulshipCanvas.height);

		this.quadTree.clear();

		this.background.init(0, 0);
		this.ship.init(this.shipStartX, this.shipStartY,
			imageRepository.spaceship.width, imageRepository.spaceship.height);
		this.enemyBulletPool.init("enemyBullet");
		this.playerScore = 0;

		//this.backgroundAudio.currentTime = 0;
		//this.backgroundAudio.play();
		this.feulStatus = scenario.maxFeulInventory;
		this.start();
		//         timer.Timer.play();
	};

	// Game over
	this.gameOver = function () {
		//	this.backgroundAudio.pause();
		//this.gameOverAudio.currentTime = 0;
		//this.gameOverAudio.play();
		document.getElementById('game-over').style.display = "block";
		$('#endScore').html(game.playerScore);
		timer.Timer.pause();
		this.ship.alive = false;
		setTimeout(function () {
			window.location = "lastForm.html?folderName=" + folderName + "&fileName=" + fileName+ "&turkSubmitTo=" + window.turkSubmitTo +"&assignmentId=" + window.assignmentId;
			  
		}, 3000);
	};
}

/**
 * Ensure the game sound has loaded before starting the game
 */
function checkReadyState() {
	if (game.gameOverAudio.readyState === 4) { //&& game.backgroundAudio.readyState === 4) {
		window.clearInterval(game.checkAudio);
		document.getElementById('loading').style.display = "none";
		game.start();
	}
}

/**
 * A sound pool to use for the sound effects
 */
function SoundPool(maxSize) {
	var size = maxSize; // Max bullets allowed in the pool
	var pool = [];
	this.pool = pool;
	var currSound = 0;

	/*
	 * Populates the pool array with the given object
	 */
	this.init = function (object) {
		if (object == "laser") {
			for (var i = 0; i < size; i++) {
				// Initalize the object
				laser = new Audio("sounds/laser.wav");
				laser.volume = .12;
				laser.load();
				pool[i] = laser;
			}
		} else if (object == "explosion") {
			for (var i = 0; i < size; i++) {
				var explosion = new Audio("sounds/explosion.wav");
				explosion.volume = .1;
				explosion.load();
				pool[i] = explosion;
			}
		}
        else if(object == "faulFill")
        {
        for (var i = 0; i < size; i++) {
				var explosion = new Audio("sounds/faul.mp3");
				explosion.volume = .1;
				explosion.load();
				pool[i] = explosion;
			}
        }
	};

	/*
	 * Plays a sound
	 */
	this.get = function () {
		if (pool[currSound].currentTime == 0 || pool[currSound].ended) {
			pool[currSound].play();
		}
		currSound = (currSound + 1) % size;
	};
}

/**
 * The animation loop. Calls the requestAnimationFrame shim to
 * optimize the game loop and draws all game objects. This
 * function must be a gobal function and cannot be within an
 * object.
 */

var counter = 0;

var freezeShipCounter = 0;
var freezeShip = false;
var gameTimer = scenario.gameLength;
var feulShipCounter = 0;
var waitForFeulShip = false;
var lastTime = 0;
var feulChartValue = 100;
var currentTime;
var scoreTime = 2;
var scoreEnd = 0;
var pauseGame = false;
var maintenaceDesable = false;

var titleX = 0;
var titleY = 0;
function animate() {
	if (pauseGame)
		return;
		
	//console.log(formatTime(gameTimer-currentTime));
	//currentTimeMin = parseInt(currentTime / 6000);
	currentTime = parseInt(window.currentTime1 / 100);
   
	if (gameTimer <= currentTime) {
		game.gameOver();
	}
    if(game.alertC.alive && window.currentTime1-game.alertC.startTime >= game.alertC.time)
    {
    game.alertC.alive = false;
    game.alertC.clear();
    }
	$("#score").html(game.playerScore);
	insertToQuadtree();
	detectCollision();
	if (freezeShip && currentTime >= freezeShipCounter) {
		stopFreezeSpaceship();
	} else if (freezeShip && currentTime <= freezeShipCounter) {
		$("#freezeSec").html(freezeShipCounter - currentTime);
	}

	// Animate game objects
	if (game.ship.alive) {
		requestAnimFrame(animate);
		controllerLoop(currentTime);
		if (game.score.alive && currentTime < scoreEnd) {
			game.score.move();
		} else if (game.score.alive && currentTime >= scoreEnd) {
			game.score.alive = false;
			game.score.clear();
		}
        if (game.scoreFace.alive && currentTime < scoreEnd) {
			game.scoreFace.move();
		} else if (game.scoreFace.alive && currentTime >= scoreEnd) {
			game.scoreFace.alive = false;
			game.scoreFace.clear();
		}
       
		if (!freezeShip) {
			game.background.draw();
			game.ship.move();
		} else {
			game.ship.context.drawImage(imageRepository.frozenship, game.ship.x, game.ship.y);
		}
        if(currentSpeed == 0)
        {
        	game.ship.context.drawImage(imageRepository.frozenship, game.ship.x, game.ship.y);
            game.ship.context.fillStyle = "yellow";          
            game.ship.context.font = "20px Arial";
            titleX = game.ship.x; titleY =  game.ship.y-30;
            game.ship.context.fillText("Ship is frozen because of severe malfunction ",  titleX, titleY);
        }

		game.techStatus.draw();
		if (!game.feulship.alive && !freezeShip && game.feulStatus >= 0) {
			if (lastTime < currentTime) {
				game.feulStatus--;
				lastTime = currentTime;
			}
			var feulStatusCalc = Math.floor(game.feulStatus / (scenario.maxFeulInventory / 100));
			if (feulChartValue - feulStatusCalc >= 1) {
				feulChartValue = feulStatusCalc;
				setFeulChart(feulChartValue);
			}
		}

		if (game.feulstation.alive) {
			game.feulstation.move();

		}

		game.ship.bulletPool.animate();
		game.enemyBulletPool.animate();
		var x = Math.floor(Math.random() * (Background.prototype.canvasWidth - 2 * imageRepository.enemyBullet.width - 20) / imageRepository.enemyBullet.width) * imageRepository.enemyBullet.width + imageRepository.enemyBullet.width + 10;
		var y = -Math.floor(Math.random() * 10) * imageRepository.enemyBullet.height;
		while (!chackEnemyBulletCollision(y, x)) {
			y = -Math.floor(Math.random() * 10) * imageRepository.enemyBullet.height;

		}
		game.enemyBulletPool.get(x, y, -6);

	}

}

function freezeSpaceship(time) {
	freezeShip = true;
	$("#maintenanceButton").attr('disabled', 'disabled');
    $("#maintenanceButton").css('cursor', 'default');
	$("#repairButton").attr('disabled', 'disabled');
    $("#repairButton").css('cursor', 'default');
	freezeShipCounter = currentTime + time;
	game.ship.context.drawImage(imageRepository.frozenship, game.ship.x, game.ship.y);
	game.ship.setSpeed(0);
	$("#freezeTitle").css("display", "block");
   
}

function stopFreezeSpaceship() {
	freezeShip = false;
    if(!maintenaceDesable){
	$("#maintenanceButton").removeAttr('disabled');    
     $("#maintenanceButton").css('cursor', 'pointer');
     }
	$("#repairButton").removeAttr('disabled');
     $("#repairButton").css('cursor', 'pointer');
	game.ship.setSpeed(currentSpeed);
	$("#freezeTitle").css("display", "none");
	game.ship.context.clearRect(game.ship.x, game.ship.y, game.ship.width, game.ship.height);
  
  

}

function increaseScore(score) {
	game.playerScore += score;
}
var properTime = scenario.mc_properTime,
minorTime = scenario.mc_minorTime,
moderateTime = scenario.mc_moderateTime,
severeTime = scenario.mc_severeTime;

function setFeulInventory(feulInvetory) {
	game.feulStatus = feulInvetory;
	feulChartValue = 100;
	setFeulChart(feulChartValue);
}

function fixStatus() {
	game.techStatus.changeStatus(1);
	techCounter = 0;
	techStatusChangeImg(1);
}
function techStatusChangeImg(techStatus) {
	switch (techStatus) {
	case 5:
		$("#mentainceButton").css("color", "Red");
		$("#mentainceButton").attr("disabled", "disabled");
		$("#mechTitle").html("death");
		$("#mechTitle").css("color", "Red");
		$("#repairButton").attr("disabled", "disabled");
		$("#repairButton").css("background-color", "Red");

		$("#repairButton").show();
		break;
	case 4:
		$("#mentainceButton").css("color", "Red");
		$("#mechTitle").html("severe failure");
		$("#mechTitle").css("color", "Red");
          $("#repCost").html(window.scenario.mc_severeActionCost);
        $("#mainCost").html(window.scenario.mc_maintenanceActionCost);
		$("#repairButton").css("background-color", "Red");
		$("#repairButton").show();
		break;
	case 3:
		$("#mentainceButton").css("color", "Orange");
		$("#mechTitle").html("moderate failure");
		$("#mechTitle").css("color", "Orange");
		$("#repairButton").css("background-color", "Orange");
          $("#repCost").html(window.scenario.mc_moderateActionCost);
        $("#mainCost").html(window.scenario.mc_maintenanceActionCost);
		$("#repairButton").show();
		break;
	case 2:
		$("#mentainceButton").css("color", "#CACA00");
		$("#mechTitle").html("minor failure");
		$("#mechTitle").css("color", "#CACA00");
		$("#repairButton").css("background-color", "#CACA00");
         $("#repCost").html(window.scenario.mc_minorActionCost);
        $("#mainCost").html(window.scenario.mc_maintenanceActionCost);
		$("#repairButton").show();
		break;
	case 1:
		$("#mentainceButton").css("color", "Green");
		$("#mechTitle").html("all well");
		$("#mechTitle").css("color", "Green");     
        $("#mainCost").html(window.scenario.mc_maintenanceActionCost);
		$("#repairButton").hide();
		break;
	}
	game.techStatus.draw();

}

function setShootingBreakPercent(precent) {
	game.ship.fireRate = precent;
}
function detectCollision() {
	if (!freezeShip) {
		var objects = [];
		game.quadTree.getAllObjects(objects);

		for (var x = 0, len = objects.length; x < len; x++) {
			game.quadTree.findObjects(obj = [], objects[x]);

			for (y = 0, length = obj.length; y < length; y++) {

				// DETECT COLLISION ALGORITHM
				if (objects[x].collidableWith === obj[y].type &&
					(objects[x].x < obj[y].x + obj[y].width &&
						objects[x].x + objects[x].width > obj[y].x &&
						objects[x].y < obj[y].y + obj[y].height &&
						objects[x].y + objects[y].height > obj[y].y)) {
					if (objects[x].type == "feulship") {
						obj[y].isColliding = false;
					} else {
						obj[y].isColliding = true;
					}
					if (objects[x].type == "enemyBullet" && objects[y].type == "ship") {
						onMeteorCollision();
						game.playerScore -= scenario.hitByMeteorScore;
						game.score.alive = true;
						game.score.init(objects[x].x + 2, objects[x].y + 2, scenario.hitByMeteorScore, false);
						game.score.move();
						scoreEnd = currentTime + scoreTime;

					} else if (objects[y].type == "enemyBullet" && objects[x].type == "bullet") {
						onMeteorShootDown();
						game.playerScore += scenario.meteorScore;
						game.score.alive = true;
						game.score.init(objects[y].x + 2, objects[y].y + 2, scenario.meteorScore,true);
						game.score.move();
						scoreEnd = currentTime + scoreTime;
					}
					objects[x].isColliding = true;

				}
			}
		}
	}
};

function Score(size) {
	this.x = 0;
	this.y = 0;
	this.size = size;
	this.init = function (x, y, number, pos) {
		this.clear();
		this.x = x;
		this.y = y;
		this.number = number;
		this.positive = pos;
		this.text = this.positive ? "+" + this.number : "-" + this.number;
        this.size = size;
     
		this.color = this.positive ? "Green" : "Red";
		this.alive = true;
		this.speed = -2;
		this.fontSpeed = 1;
		
	}

	this.draw = function () {
		this.context.font = this.size + 'pt Calibri';
		this.context.fillStyle = this.color;
		this.context.fillText(this.text, this.x, this.y);
	}
	this.clear = function () {
   
		this.context.clearRect(this.x - 2 * this.size, this.y - 2 * this.size, 6 * this.size, 7 * this.size);
	

    }
	this.move = function () {
		this.clear();
		this.x += this.speed;
		this.y += this.speed;
		this.size += this.fontSpeed;
		this.draw();
	}

}


function AlertC(size) {
	this.x = 0;
	this.y = 0;
	this.size = size;
	this.init = function (x, y, text, time) {
		this.clear();
		this.x = x;
		this.y = y;
		this.text = text;      
        this.time = time;
		this.color = "orange";
		this.alive = true;
        this.startTime = window.currentTime1;		
		
	}

	this.draw = function () {
		this.context.font = this.size + 'pt Calibri';
		this.context.fillStyle = this.color;
		this.context.fillText(this.text, this.x, this.y);
	}
	this.clear = function () {
   
		this.context.clearRect(this.x - 2 * this.size, this.y - 2 * this.size, 60 * this.size, 7 * this.size);
	

    }
	

}


function ScoreFace() {
	this.x = 0;
	this.y = 0;
	
	this.init = function (x, y, tec) {
		this.clear();
		this.x = x;
		this.y = y;
		this.tec = tec;	
        switch (tec)
        {
        case 2:
        this.text = "minor failure";
        imageRepository.techStatus.src = "imgs/smile" + tec + ".png";
        break;        
        case 3:
       this.text = "moderate failure";
       imageRepository.techStatus.src = "imgs/smile" + tec + ".png";
        break;
        case 4:
        this.text = "severe failure";
        imageRepository.techStatus.src = "imgs/smile" + tec + ".png";
        break;        
        }			
      
		this.color = "Red";
		this.alive = true;
		this.speed = -2;
		this.fontSpeed = 1;
		
	}

	this.draw = function () {
		this.context.font ='14pt Calibri';
		this.context.fillStyle = this.color;
		this.context.fillText(this.text, this.x-60, this.y-5);	
		this.context.drawImage(imageRepository.techStatus, this.x-60 , this.y+5 );

	};
	
	this.clear = function () {
    
   
    this.context.clearRect(this.x-70, this.y-80, imageRepository.techStatus.width+120, imageRepository.techStatus.height+120);

    }
	this.move = function () {
		this.draw();
	}

}

function chackEnemyBulletCollision(y, x) {
	var height = imageRepository.enemyBullet.height;
	for (var i = 0; i < game.enemyBulletPool.count; i++) {

		if (game.enemyBulletPool[i].alive && game.enemyBulletPool[i].x == x && game.enemyBulletPool[i].y < y + height && enemyBulletPool[i].y + height > y) {
			return false;
		}
	}
	return true;
}

// The keycodes that will be mapped when a user presses a button.
// Original code by Doug McInnes
KEY_CODES = {
	32 : 'space',
	37 : 'left',
	38 : 'up',
	39 : 'right',
	40 : 'down',
}

// Creates the array to hold the KEY_CODES and sets all their values
// to true. Checking true/flase is the quickest way to check status
// of a key press and which one was pressed when determining
// when to move and which direction.
KEY_STATUS = {};
for (code in KEY_CODES) {
	KEY_STATUS[KEY_CODES[code]] = false;
}
/**
 * Sets up the document to listen to onkeydown events (fired when
 * any key on the keyboard is pressed down). When a key is pressed,
 * it sets the appropriate direction to true to let us know which
 * key it was.
 */
document.onkeydown = function (e) {
	// Firefox and opera use charCode instead of keyCode to
	// return which key was pressed.
	var keyCode = (e.keyCode) ? e.keyCode : e.charCode;
	if (KEY_CODES[keyCode]) {
		e.preventDefault();
		KEY_STATUS[KEY_CODES[keyCode]] = true;
	}
}
/**
 * Sets up the document to listen to ownkeyup events (fired when
 * any key on the keyboard is released). When a key is released,
 * it sets teh appropriate direction to false to let us know which
 * key it was.
 */
document.onkeyup = function (e) {
	var keyCode = (e.keyCode) ? e.keyCode : e.charCode;
	if (KEY_CODES[keyCode]) {
		e.preventDefault();
		KEY_STATUS[KEY_CODES[keyCode]] = false;
	}
}

function insertToQuadtree() {
	game.quadTree.clear();
	game.quadTree.insert(game.ship);
	game.quadTree.insert(game.ship.bulletPool.getPool());
	game.quadTree.insert(game.enemyBulletPool.getPool());
	game.quadTree.insert(game.feulstation);
}

function makeAnewFeulStation(x) {
	game.feulstation.context.clearRect(game.feulstation.x - 1, game.feulstation.y - 1, game.feulstation.width + 2, game.feulstation.height + 2);
	var xFeul = x;
	var yFeul = -imageRepository.feulstation.height;
	game.feulstation.init(xFeul, yFeul, imageRepository.feulstation.width, imageRepository.feulstation.height);
	game.feulstation.alive = true;
	game.feulstation.move();

}
function callToFeulSpaceship(time) {
	if (!game.feulship.alive && !waitForFeulShip) {
		game.feulship.context.clearRect(game.feulship.x - 1, game.feulship.y - 1, game.feulship.width + 2, game.feulship.height + 2);
		feulShipCounter = currentTime + time - scenario.fs_actionTime;
		freezeSpaceship(time);
		game.feulship.init(0, 0, imageRepository.feulship.width, imageRepository.feulship.height);
		game.feulship.draw();
		waitForFeulShip = true;

	}
	if (currentTime >= feulShipCounter) {
		waitForFeulShip = false;
		game.feulship.alive = true;
		game.feulship.move();
	}

}

function changeMechanicalCondition(newStatus) {
	if (game.techStatus.status == newStatus) {
		//console.warning("logical mistake - change status to current status (" + newStatus +")");
	}
	changeShooting = false;
	changeSpeed = false;
	game.techStatus.changeStatus(newStatus);
	techStatusChangeImg(game.techStatus.status);
}
/**
 * requestAnim shim layer by Paul Irish
 * Finds the first API that works to optimize the animation loop,
 * otherwise defaults to setTimeout().
 */
window.requestAnimFrame = (function () {
	var ret = window.requestAnimationFrame ||
		window.webkitRequestAnimationFrame ||
		window.mozRequestAnimationFrame ||
		window.oRequestAnimationFrame ||
		window.msRequestAnimationFrame ||
	function (/* function */
		callback, /* DOMElement */
		element) {
		window.setTimeout(callback, 1000 / 60);
	};
	return ret;
})();
